package coffeenc.mall.common.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    @Value("${jwt.expiration}")
    private Long expiration;
    @Value("${jwt.secret}")
    private String secret;

    /**
     * 生成Token的过期时间
     */
    private Date generateExpirationDate(){
        return new Date(System.currentTimeMillis()+expiration*1000);
    }

    /**
     * 根据Map<String,Object>对象生成的claims来生成token字符串
     */
    private String generateToken(Map<String,Object> claims){
         return Jwts.builder()    /* 生成一个DefaultJwtBuilder对象并返回 */
                .setClaims(claims)    /* token的数据声明，也就是token的负载部分内容 */
                .setExpiration(generateExpirationDate())    /* 设置token的过期时间 */
                .signWith(SignatureAlgorithm.HS512,secret)    /* 设置签名方式，包括签名算法和密钥 */
                .compact();    /* 拼接，形成token字符串并返回 */
    }

    /**
     * 根据UserDetails对象生成token字符串
     * 该方法的主要功能是从UserDetails对象中分离出一定信息形成claims
     * token的生成操作实际上是委托给其重载方法完成
     */
    public String generateToken(UserDetails userDetails){
        Map<String,Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, LocalDateTime.now());
        return generateToken(claims);
    }

    /**
     * 从token字符串中获取数据声明
     */
    private Claims getClaimsFromToken(String token){
        Claims claims = null;
        claims = Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
        return claims;
    }

    /**
     * 验证token中存储的用户信息是否有效
     */
    public boolean validateToken(String token,UserDetails userDetails){
        String username = getUserNameFromToken(token);
        return userDetails.getUsername().equals(username) && !isTokenExpired(token);
    }

    /**
     * 判断token是否过期
     */
    private boolean isTokenExpired(String token){
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中解析出用户名
     */
    public String getUserNameFromToken(String token){
        Claims claims = getClaimsFromToken(token);
        return claims.getSubject();
    }
    /**
     * 从token中解析出过期时间
     */
    private Date getExpiredDateFromToken(String token){
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }
}
